import {
  format,
  autoFixed,
  getDataType
} from '../utils/utils.js'
import {
  recordStatusEnum
} from '../utils/enum.js'
class Paint {
  constructor(args) {
    const {
      canvasId,
      timeId,
      canvasConfig
    } = args
    if (!canvasId || !timeId) {
      console.error('LveRecord: canvasId 和 timeId为必传项')
      return
    }
    this.canvas = canvasId // 画布dom
    this.context = canvasId.getContext('2d') // 画布对象
    this.canvasConfig = canvasConfig
    this.canvasHistory = [] // 历史栈
    this.time = 0 // 当前时间
    this.timer = null // 录制时间定时器
    this.timeDom = timeId // 时间展示dom
    this.lastTime = 0 // 上一次记录的时间
    this.timeStepUnit = 25 // 录制时间间隔
    this.status = recordStatusEnum.Ready // 录制状态
    this.initCanvas()
    this.initTime()
  }
  /**
   * 检查画布是否完成初始化
   **/
  ready = () => {
    return new Promise((resolve, reject) => {
      if (!this.canvas || !this.context) {
        console.warn('LveRecord: 画布未初始化')
        reject()
      }
      resolve()
    })
  }
  /**
   * 获取当前录制实例的状态
   **/
  getStatus = () => {
    return this.status
  }
  /**
   * 设置录制时间间隔（间隔越小绘制越精细，但是数据量也会越大）（单位毫秒）
   **/
  setTimeStep = (stepUnit) => {
    this.timeStepUnit = stepUnit
  }
  /**
   * 获取录制时间间隔（单位毫秒）
   **/
  getTimeStep = () => {
    return this.timeStepUnit
  }
  /**
   * 获取录制数据
   **/
  getData = () => {
    return this.canvasHistory
  }
  /**
   * 获取画笔颜色
   **/
  getPenColor = async () => {
    const color = await this.ready().then(() => {
      return this.context.fillStyle
    })
    return color
  }
  /**
   * 设置画笔颜色
   * @param color 画笔颜色
   **/
  setPenColor = color => {
    this.context.strokeStyle = color ?? '#000';
  }
  /**
   * 获取画笔尺寸
   **/
  getPenSize = async () => {
    const size = await this.ready().then(() => {
      return this.context.lineWidth
    })
    return size
  }
  /**
   * 设置画笔尺寸
   * @param size 画笔尺寸
   **/
  setPenSize = size => {
    this.context.lineWidth = size
  }
  /**
   * 获取画布背景颜色
   **/
  getBgColor = async () => {
    const bgColor = await this.ready().then(() => {
      return this.context.fillStyle
    })
    return bgColor
  }
  /**
   * 设置画布背景颜色
   * @param bgColor 背景颜色
   **/
  setBgColor = bgColor => {
    this.context.fillStyle = bgColor
    this.context.fillRect(0, 0, this.canvas.width, this.canvas.height)
  }
  /**
   * 事件初始化
   **/
  initEvent = () => {
    this.canvas.addEventListener('mousedown', this.startAction);
    // 当鼠标移除canvas区域时，主动结束canvas onmousemove onmouseup事件, 防止mouse相关时间失效导致对数据的影响
    this.canvas.addEventListener('mouseleave', this.mouseleaveAction);
  }
  /**
   * canvas dom移出边界限制
   */
  mouseleaveAction = (e) => {
    if (this.status === recordStatusEnum.Ing) {
      const type = getDataType(this.canvasHistory[this.canvasHistory.length - 1])
      // 在超出边界时，主动停止onmousemove事件，并且主动设置当次 笔结束点
      if (type !== 'object') {
        this.context.closePath();
        this.canvasHistory[this.canvasHistory.length - 1].push({
          f: 'pen',
          s: 'end',
          x: e.offsetX,
          y: e.offsetY,
          t: autoFixed(this.time - this.lastTime, 3),
          ct: autoFixed(this.time, 3) // 当前时间
        })
        this.lastTime = this.time
        this.canvas.removeEventListener('mousemove', this.moveAction)
        this.canvas.removeEventListener('mouseup', this.endAction);
      }
    }
  }
  /**
   * 开始录制
   **/
  startRecord = (stream) => {
    this.initEvent()
    this.clear()
    this.timer = setInterval(() => {
      this.time += autoFixed(this.timeStepUnit / 1000, 3)
      this.timeDom.textContent = format(this.time)
    }, this.timeStepUnit)
    this.status = recordStatusEnum.Ing
  }
  /**
   * 暂停录制
   **/
  pauseRecord = () => {
    clearInterval(this.timer)
    this.timer = null
    this.status = recordStatusEnum.Paused
  }
  /**
   * 继续录制
   **/
  resumeRecord = () => {
    if (!this.timer) {
      this.timer = setInterval(() => {
        this.time += autoFixed(this.timeStepUnit / 1000, 3)
        this.timeDom.textContent = format(this.time)
      }, this.timeStepUnit)
      this.status = recordStatusEnum.Ing
    }
  }
  /**
   * 结束录制
   **/
  stopRecord = () => {
    this.canvasHistory.push({
      f: 'system',
      s: 'stop',
      t: autoFixed(this.time - this.lastTime, 3),
      ct: autoFixed(this.time, 3)
    })
    this.timer && clearInterval(this.timer)
    this.time = 0
    this.lastTime = 0
    this.status = recordStatusEnum.End
  }
  /**
   * 修改canvas背景颜色
   */
  changeBgColor = (e) => {
    if (this.status !== recordStatusEnum.Ing) {
      console.warn('LveRecord: 请在开始录制后改变背景颜色')
      return
    }
    this.canvasHistory.push({
      f: 'system',
      s: {
        bgColor: e
      },
      t: autoFixed(this.time - this.lastTime, 3),
      ct: autoFixed(this.time, 3)
    })
    this.lastTime = this.time
    // 设置fillStyle同时一定要设置fillRect，不然无法生效
    this.setBgColor(e)
  }
  /**
   * 修改canvas画笔颜色
   */
  changePenColor = e => {
    if (this.status !== recordStatusEnum.Ing) {
      console.warn('LveRecord: 请在开始录制后改变画笔颜色')
      return
    }
    this.canvasHistory.push({
      f: 'system',
      s: {
        penColor: e
      },
      t: autoFixed(this.time - this.lastTime, 3),
      ct: autoFixed(this.time, 3)
    })
    this.lastTime = this.time
    // 设置画笔颜色
    this.setPenColor(e)
  }
  /**
   * 修改canvas画笔尺寸
   */
  changePenSize = e => {
    if (this.status !== recordStatusEnum.Ing) {
      console.warn('LveRecord: 请在开始录制后改变画笔尺寸')
      return
    }
    this.canvasHistory.push({
      f: 'system',
      s: {
        penSize: e
      },
      t: autoFixed(this.time - this.lastTime, 3),
      ct: autoFixed(this.time, 3)
    })
    this.lastTime = this.time
    // 设置画笔尺寸
    this.context.lineWidth = e
  }
  /**
   * 插入本地背景图片
   **/
  insertImage = () => {
    if (this.status !== recordStatusEnum.Ing) {
      console.warn('LveRecord: 请在开始录制后插入背景图片')
      return
    }
    const inputObj = document.createElement('input');
    // 不能改变this指向，并且要调用外部方法
    inputObj.addEventListener('change', this.readFile.bind(inputObj, this), false);
    inputObj.type = 'file';
    inputObj.accept = 'image/*';
    inputObj.click();
    this.pauseRecord()
  }
  /**
   * 解析本地图片并转化为base64
   **/
  readFile = function(comp) {
    const file = this.files[0]; // 获取input输入的图片
    if(!/image\/\w+/.test(file.type)){
        alert("请确保文件为图像类型");
        return false;
    } // 判断是否图片
    const reader = new FileReader();
    reader.readAsDataURL(file); // 转化成base64数据类型
    reader.onload = function(e){
      comp.drawLocalImageToCanvas(this.result);
    }
  }
  /**
   * 绘制本地图片到canvas上（画板区）
   **/
  drawLocalImageToCanvas = (imgData) => {
    const canvasImage = document.querySelector('#canvas-image')
    canvasImage.style.backgroundImage = `url(${imgData})`
    this.canvasHistory.push({
      f: 'image',
      s: imgData,
      t: autoFixed(this.time - this.lastTime, 3),
      ct: autoFixed(this.time, 3)
    })
    this.lastTime = this.time
    this.resumeRecord()
  }
  /**
   * canvas涂鸦事件开始
   **/
  startAction = (e) => {
    if (this.status !== recordStatusEnum.Ing) return
    this.context.beginPath();
    this.context.moveTo(e.offsetX, e.offsetY);
    this.context.stroke();
    this.canvasHistory.push([{
      f: 'pen',
      s: 'start',
      x: e.offsetX,
      y: e.offsetY,
      t: autoFixed(this.time - this.lastTime, 3),
      ct: autoFixed(this.time, 3) // 当前时间
    }])
    this.lastTime = this.time
    this.canvas.addEventListener('mousemove', this.moveAction);
    this.canvas.addEventListener('mouseup', this.endAction);
  }
  /**
   * canvas涂鸦事件过程
   **/
  moveAction = (e) => {
    if (this.status !== recordStatusEnum.Ing) return
    const type = getDataType(this.canvasHistory[this.canvasHistory.length - 1])
    if (type === 'object') return
    this.context.lineTo(e.offsetX, e.offsetY);
    this.context.stroke();
    this.canvasHistory[this.canvasHistory.length - 1].push({
      f: 'pen',
      s: 'ing',
      x: e.offsetX,
      y: e.offsetY,
      t: autoFixed(this.time - this.lastTime, 3), // 与上一个操作的时间间隔
      ct: autoFixed(this.time, 3) // 当前时间
    })
    this.lastTime = this.time
  }
  /**
   * canvas涂鸦事件结束
   **/
  endAction = (e) => {
    if (this.status !== recordStatusEnum.Ing) return
    const type = getDataType(this.canvasHistory[this.canvasHistory.length - 1])
    if (type === 'object') return
    this.context.closePath();
    this.canvasHistory[this.canvasHistory.length - 1].push({
      f: 'pen',
      s: 'end',
      x: e.offsetX,
      y: e.offsetY,
      t: autoFixed(this.time - this.lastTime, 3),
      ct: autoFixed(this.time, 3) // 当前时间
    })
    this.lastTime = this.time
    this.canvas.removeEventListener('mousemove', this.moveAction);
    this.canvas.removeEventListener('mouseup', this.endAction);
  }
  /**
   * 初始化canvas
   **/
  initCanvas = () => {
    // 设置canvas宽高
    this.canvas.width = this.canvasConfig?.width ?? 800
    this.canvas.height = this.canvasConfig?.height ?? 400
    // 笔触样式
    this.context.lineWidth = this.canvasConfig?.lineWidth ?? 5
    this.context.fillStyle = '#fff'
    this.context.fillRect(0, 0, this.canvas.width, this.canvas.height)
  }
  /**
   * 清除canvas 并且清除历史记录
   **/
  clear = () => {
    this.context?.clearRect(0, 0, this.canvas.width, this.canvas.height)
    this.canvasHistory = []
  }
  /**
   * 初始化时间
   **/
  initTime = () => {
    this.timeDom.textContent = format(this.time)
  }
}

export default Paint